﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Irrlicht.Net;
using Irrlicht.Net.Core;
using Irrlicht.Net.GUI;
using Irrlicht.Net.IO;
using Irrlicht.Net.Scene;
using Irrlicht.Net.Video;

namespace Tutorial2
{
    class Program
    {
        static int Main(string[] args)
        {
            // Like in the HelloWorld example, we create an IrrlichtDevice with new Device(). 
            // The difference now is that we ask the user to select which video driver to use. 
            // The Software device might be too slow to draw a huge Quake 3 map, but just for the fun of it, 
            // we make this decision possible, too.

            // ask user for driver
            DriverTypes driverType = DriverChoice.FromConsole();

            if (driverType == DriverTypes.Count)
            {
                // Failed getting driver type.
                return 1;
            }            

            // create device and exit if creation failed
            Device device = new Device(driverType, new Dimension2D(640, 480), false);

            if (device == null)
            {
                // could not create selected driver.
                return 1;
            }

            string mediaPath = "../../../../../media/";

            // Get a pointer to the video driver and the SceneManager so that we do not
            // always have to call Device.VideoDriver and Device.SceneManager. 
            VideoDriver driver = device.VideoDriver;
            SceneManager scene = device.SceneManager;

            // To display the Quake 3 map, we first need to load it. Quake 3 maps are packed into .pk3
            // files which are nothing else than .zip files. So we add the .pk3 file to our Device.FileSystem. 
            // After it was added, we are able to read from the files in that archive as if they are directly stored on the disk. 
            bool result = device.FileSystem.AddZipFileArchive(mediaPath + "map-20kdm2.pk3");
            
            // Now we can load the mesh by calling Scene.GetMesh(). We get a pointer returned to an AnimatedMesh. 
            // As you might know, Quake 3 maps are not really animated, they are only a huge chunk of static geometry 
            // with some materials attached. Hence the AnimatedMesh consists of only one frame, so we get the "first frame" of the "animation", 
            // which is our quake level and create an Octree scene node with it, using Scene.AddOctree(). 
            // The Octree optimizes the scene a little bit, trying to draw only geometry which is currently visible. 
            // An alternative to the Octree would be a Scene.MeshSceneNode, which would always draw the complete geometry of the mesh, 
            // without optimization. Try it: Use Scene.AddMeshSceneNode() instead of AddOctree() and 
            // compare the primitives drawn by the video driver. (There is a Video.GetPrimitiveCountDrawn() method in the VideoDriver class). 
            // Note that this optimization with the Octree is only useful when drawing huge meshes consisting of lots of geometry. 
            AnimatedMesh mesh = scene.GetMesh("20kdm2.bsp");        
            SceneNode node = null;

            if (mesh != null)
            {
                node = scene.AddOctree(mesh, 1024);
            }

            // Because the level was not modelled around the origin (0,0,0), we translate the whole level a little bit. 
            // This is done on SceneNode level using the methods Node.Position (in this case), Node.Rotation, and Node.Scale. 

            if (node != null)
            {
                node.Position =  new Vector3D(-1300,-144,-1249);
            }
    
            // Now we only need a camera to look at the Quake 3 map. We want to create a user controlled camera. 
            // There are some cameras available in the Irrlicht engine. For example the MayaCamera which can be controlled like the
            // camera in Maya: Rotate with left mouse button pressed, Zoom with both buttons pressed, translate with right mouse button pressed. 
            // This could be created with Scene.AddCameraSceneNodeMaya(). 
            // But for this example, we want to create a camera which behaves like the ones in first person shooter games (FPS)
            // and hence use Scene.AddCameraSceneNodeFPS().         
            scene.AddCameraSceneNodeFPS();

            //The mouse cursor needs not be visible, so we hide it via the Device.CursorControl. 
            device.CursorControl.Visible = false;

            // We have done everything, so lets draw it. We also write the current frames per second and the primitives drawn into the
            // caption of the window. The test for device.IsWindowActive is optional, but prevents the engine to grab the 
            // mouse cursor after task switching when other programs are active. The call to Device.Yield() will avoid the
            // busy loop to eat up all CPU cycles when the window is not active. 
            int lastFPS = -1;
        
            while(device.Run())
            {
                if (device.IsWindowActive)
                {                        
                    driver.BeginScene(true, true, new Color(255,200,200,200));                        
                    scene.DrawAll();                        
                    driver.EndScene();
                        
                    int fps = driver.FPS;
                        
                    if (lastFPS != fps)
                    {
                        string str = "Irrlicht Engine - Quake 3 Map example [" +
                            driver.Name + "] FPS:" +  fps;
                        device.WindowCaption = str;                        
                        lastFPS = fps;
                    }
                }
                else
                {                 
                    device.Yield();
                }
            }

            // In the end, delete the Irrlicht device.
            device.Dispose();
            return 0;
        }
    }
}
